package com.bonnemai.eqd.server;

import java.text.SimpleDateFormat;
import java.util.logging.Logger;

import org.jquantlib.Settings;
import org.jquantlib.daycounters.Actual365Fixed;
import org.jquantlib.daycounters.DayCounter;
import org.jquantlib.exercise.EuropeanExercise;
import org.jquantlib.exercise.Exercise;
import org.jquantlib.instruments.EuropeanOption;
import org.jquantlib.instruments.Option;
import org.jquantlib.instruments.Payoff;
import org.jquantlib.instruments.PlainVanillaPayoff;
import org.jquantlib.instruments.VanillaOption;
import org.jquantlib.pricingengines.AnalyticEuropeanEngine;
import org.jquantlib.processes.BlackScholesMertonProcess;
import org.jquantlib.quotes.Handle;
import org.jquantlib.quotes.Quote;
import org.jquantlib.quotes.SimpleQuote;
import org.jquantlib.termstructures.BlackVolTermStructure;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.termstructures.volatilities.BlackConstantVol;
import org.jquantlib.termstructures.yieldcurves.FlatForward;
import org.jquantlib.time.Calendar;
import org.jquantlib.time.Date;
import org.jquantlib.time.calendars.Target;

import com.bonnemai.eqd.shared.Vanilla;

public class EquityOption {
	static Logger LOG = Logger.getLogger(EquityOption.class.getName());
	
	private VanillaOption jQuantLibVanillaOption;
	SimpleDateFormat DD = new SimpleDateFormat("dd");
	SimpleDateFormat MM = new SimpleDateFormat("MM");
	SimpleDateFormat YYYY = new SimpleDateFormat("yyyy");
	
	private Date getDate(java.util.Date d){
		int days = Integer.valueOf(DD.format(d)).intValue();
		int month= Integer.valueOf(MM.format(d)).intValue();
		int years = Integer.valueOf(YYYY.format(d)).intValue();
		Date result = new Date(days, month, years);
		LOG.info(d + " -> "+ result);
		return result;		
	}
	
	
	public EquityOption(Vanilla vanilla) {
		LOG.info("Pricing Vanilla: "+vanilla);
		
		final Calendar calendar = new Target();
		Date todaysDate=getDate(vanilla.getTodaysDate());
		Date settlementDate=getDate(vanilla.getSettlementDate());
		Date maturityDate=getDate(vanilla.getMaturityDate());
		
		new Settings().setEvaluationDate(todaysDate);
		
		// our options
		Option.Type optionType = Option.Type.Call;
		if (vanilla.getType() !=null && vanilla.getType().equalsIgnoreCase("put")){
			//final Option.Type type = Option.Type.Put;
			optionType = Option.Type.Put;
			Logger.getAnonymousLogger().info(optionType.toString());
		}

		final DayCounter dayCounter = new Actual365Fixed();
	         
		// Define exercise for European Options
		final Exercise europeanExercise = new EuropeanExercise(maturityDate);
		 
		// bootstrap the yield/dividend/volatility curves
		final Handle<Quote> underlyingH = new Handle<Quote>(new SimpleQuote(vanilla.getSpot()));
		final Handle<YieldTermStructure> flatDividendTS = new Handle<YieldTermStructure>(new FlatForward(settlementDate, vanilla.getDividendYield(), dayCounter));
		final Handle<YieldTermStructure> flatTermStructure = new Handle<YieldTermStructure>(new FlatForward(settlementDate, vanilla.getRiskFreeRate(), dayCounter));
		final Handle<BlackVolTermStructure> flatVolTS = new Handle<BlackVolTermStructure>(new BlackConstantVol(settlementDate, calendar, vanilla.getVolatility(), dayCounter));
		final Payoff payoff = new PlainVanillaPayoff(optionType, vanilla.getStrike());
		final BlackScholesMertonProcess bsmProcess = new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS);
		 
		// European Options
		jQuantLibVanillaOption = new EuropeanOption(payoff, europeanExercise);
		// TODO: add American/ change Pricing Method
		
		// Black-Scholes for European
		jQuantLibVanillaOption.setPricingEngine(new AnalyticEuropeanEngine(bsmProcess));
	}

	
	
	public VanillaOption getJQuantLibVanillaOption() {
		return jQuantLibVanillaOption;
	};



	public static void main(String[] s){
		Vanilla vanilla=new Vanilla ();
		
		vanilla.setStrike(100);
		vanilla.setSpot(80);

		vanilla.setDividendYield(.03);
		vanilla.setType("call");
		vanilla.setRiskFreeRate(.05);
		vanilla.setVolatility(.20);
		
		long now=System.currentTimeMillis();
		long lMatu=now+365*24*60*60*1000l;
		java.util.Date dMatu = new java.util.Date(lMatu);
		LOG.info("dMatu: "+dMatu);
		
		vanilla.setMaturityDate(dMatu );
		vanilla.setTodaysDate(new java.util.Date());
		vanilla.setSettlementDate(new java.util.Date());
		
		EquityOption equityOption=new EquityOption(vanilla);
		
		LOG.info("NPV: "+ equityOption.getJQuantLibVanillaOption().NPV());
		LOG.info("Delta: "+ equityOption.getJQuantLibVanillaOption().delta());
		LOG.info("Gamma: "+ equityOption.getJQuantLibVanillaOption().gamma());
		LOG.info("Vega: "+ equityOption.getJQuantLibVanillaOption().vega());
	}
}
